package com.gopay.checkorder.service.task;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.gopay.gass.service.GassPayRemoteService;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gopay.checkorder.dao.BisBankOrderQueryDAO;
import com.gopay.checkorder.manager.BankOrderManager;
import com.gopay.checkorder.service.BankOrderService;
import com.gopay.checkorder.service.BcdlOrderSendBankService;
import com.gopay.checkorder.service.sentinel.BcdlOrderSentinel;
import com.gopay.common.constants.autosettle.SettlementExchangeConstants;
import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.bank.BankOrderType;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.BisBankInterfaceChannel;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.cps.manager.order.CpsGeneralMainOrderQueryManager;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BcdlResult;
import com.gopay.common.exception.GopayException;
import com.gopay.common.order.dao.CommonQueryDAO;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.HttpTransport;
import com.gopay.common.util.StringTools;
import com.gopay.common.util.spring.SpringContextUtil;

public class BcdlOrderSendEmitterTaskImpl implements Task {
	private final static Logger logger = LoggerFactory.getLogger(BcdlOrderSendEmitterTaskImpl.class);

	@Resource(name = "bankOrderService")
	private BankOrderService bankOrderService;
	private int MAX_SIZE=100;
	
    @Resource(name = "cpsGeneralMainOrderQueryManager")
    protected CpsGeneralMainOrderQueryManager mainOrderQuery;
    @Resource(name = "bankOrderManager")
    protected BankOrderManager bankOrderManager;
    @Resource(name = "bisBankOrderQueryDAO")
    private BisBankOrderQueryDAO bisBankOrderQueryDAO;

    @Resource(name = "commonQueryDAO")
    private CommonQueryDAO commonQueryDAO;
	@Resource(name = "gassPayService")
	private GassPayRemoteService gassPayService;
	private String bank;
	private String label;
	private int remainder;
    private int modInt;
    private String across;
    
    private BcdlOrderSentinel sentinel;
    
    @Resource(name = "bcdlConfig")
	private Map<String, String> bcdlConfig;
    
	@Override
	public void doTask() {
	    logger.info("label_"+label+"银企直连付款job--开始，bank="+bank);
        process(bank);
        logger.info("label_"+label+"银企直连付款job--结束，bank="+bank);
	}

	public void process(String bank) {
		if(sentinel.isFuse()){
			logger.error("label_"+label+bank+",暂停付款任务");
			
			oneTestOrder(bank, sentinel);
			return;
		}
		
		// modified by zyt,2017-10-10,抽出公用的合法时间校验到bankOrderManager中，时间校验前置，防止查询db后又被时间拦截，浪费db与服务的io
		if (!bankOrderManager.isLegalTime(bank)) {
			return;
		}
		
		
		try {
		    StopWatch sw=new StopWatch();
		    sw.start();
		    List<String> sendOrders = getSendBankOrder(bank);
			sw.split();
            logger.error("label_"+label+bank+"-----------getSendBankOrder耗时="+sw.getSplitTime());
			
			logger.error("label_"+label+"-----------"+bank+"发往银行记录总数="+sendOrders.size());
			
			
			// 继续对账
			String beanName = getSendBankBeanName(bank);
			if (false == SpringContextUtil.containsBean(beanName)) {
				logger.info("label_"+label+"spring bean does not exist: " + beanName);
				return;
			}
			
			BcdlOrderSendBankService sendBankService = (BcdlOrderSendBankService) SpringContextUtil
					.getBean(beanName);
			HttpTransport notifyGass = new HttpTransport();
            notifyGass.setSendEncoding("UTF-8");
			for (String bankOrderId : sendOrders) {
				BcdlResult result = null;
				BankOrder bankOrder = bisBankOrderQueryDAO.find(BankOrder.class, bankOrderId);
				try{
					// 非生产环境、非一分钱交易直接置为“99”失败
					if (!"prod".equals(bcdlConfig.get("sys.id")) && !"0.01".equals(bankOrder.getSendBankAmt().toString())) {
						bankOrderManager.updateFail(bankOrder);
					}else{
                    if (!isLargeCrossWorkTime(new Date())) {
                        // 工行跨行大额订单增加发送时间限制
                        if (SettlementExchangeConstants.STLM_EX_ICBC_CROSS.equals(getStlmEx(bankOrder.getOrderId()))) {
                            logger.error(bankOrder.getOrderId()
                                    + " BcdlOrderSendEmitterTaskImpl process not isLargeCrossWorkTime");
                            continue;
                        }
                    }
                    logger.error("插入发往银行日志--开始 ，orderId="+bankOrder.getOrderId()+",bank="+bank);
        			bankOrderManager.saveCheckBcdlSendBankLog(bankOrder);
        			logger.error("插入发往银行日志--结束 ，orderId="+bankOrder.getOrderId()+",bank="+bank);
    				logger.error("label_"+label+"银企直连 发送银行--开始 ，orderId="+bankOrder.getOrderId()+",bank="+bank);
    				result =sendBankService.sendBank(bankOrder,label);
    				logger.error("label_"+label+"银企直连 发送银行--结束 ，orderId="+bankOrder.getOrderId()+",bank="+bank+",resultCode="+result.getResultCode());
    				
    				Map<String, String> param = new HashMap<String, String>();
    				if (ProcCodeConstants.PROC_CODE_100E6027.equals(result.getResultCode()) ) {
    					param.put("resultCode", "2");
    					param.put("resultMsg", result.getErrorMsg());
    					param.put("remark", "1");
    					param.put("gopayOrderId", bankOrder.getOrderId());

						//add by zyt,2017-10-13 ,是否需要做失败的拒绝账务，
						if(result.isNeedRefund()){
							logger.info("发起失败拒绝账务：orderId:" + bankOrder.getOrderId());
							param.put("needRefund", "1");
						}

    					/*notifyGass.setUrl(bankOrder.getRemark2());
    					notifyGass.submit(param);*/ // 生产优化10期 lx httpclient 替换为 hessian
						gassPayService.bcdlNotifyGass(param);
    				}else if(ProcCodeConstants.PROC_CODE_100S1000.equals(result.getResultCode()) ){
    					param.put("resultCode", "1");
    					param.put("remark", "1");
    					param.put("gopayOrderId", bankOrder.getOrderId());
    					/*notifyGass.setUrl(bankOrder.getRemark2());
    					notifyGass.submit(param);*/ // 生产优化10期 lx httpclient 替换为 hessian
						gassPayService.bcdlNotifyGass(param);
    				}else if(ProcCodeConstants.PROC_CODE_100E6047.equals(result.getResultCode()) ){
    					logger.error("label_"+label+"银企直连 超时休眠--开始 ，orderId="+bankOrder.getOrderId()+",bank="+bank);
    					Thread.sleep(5000);
    					logger.error("label_"+label+"银企直连 超时休眠--结束 ，orderId="+bankOrder.getOrderId()+",bank="+bank);
    				}else{
    					param.put("resultCode", "3");
    					param.put("remark", "1");
    					param.put("gopayOrderId", bankOrder.getOrderId());
    					/*notifyGass.setUrl(bankOrder.getRemark2());
    					notifyGass.submit(param);*/ // 生产优化10期 lx httpclient 替换为 hessian
						gassPayService.bcdlNotifyGass(param);
    				}
					}
				} catch (Exception e) {
				    logger.error("label_"+label+"发送银行异常 ，orderId="+bankOrder.getOrderId()+",bank="+bank,e);
		        }finally{
		        	sentinel.patrol(bankOrder,result);
		        	if(sentinel.isFuse()){
						logger.error("label_"+label+bank+",暂停付款任务");
						break;
					}
		        }
				

			}
		} catch (Exception e) {
			logger.error("label_"+label+"checkOrder error message: ,bank="+bank, e);
		}
	}
	
	
	public List<Object[]> getCheckBcdlOrderByBank(String bank,String orderStatus,int modInt,int remainder,String across,int pageIndex, int pageSize){
    	StringBuffer sql = new StringBuffer(250);
    	sql.append("select b.GOPAY_OUT_ORDER_ID,b.GOPAY_ORDER_ID from BIS_BANK_MAIN_ORDER b ");
    	if(StringUtils.isNotBlank(across)){
    		sql.append(" left join BIS_BANK_BCDL_ORDER o on o.gopay_out_order_id = b.gopay_out_order_id ");
    	}
    	sql.append(" left join checkorder_bcdl_send_bank_log c on b.gopay_order_id = c.gopay_order_id ");
    	sql.append(" where b.ORDER_STATUS = :orderStatus ");
    	if(modInt!=1){
			sql.append(" and mod(b.GOPAY_ORDER_ID,:modInt)=:remainder ");
		}
    	sql.append(" and b.BANK_BIZ_PROD_CODE = :bankBizProdCode ");
    	// 获取订单增加渠道码条件
        sql.append(" and b.INTRFACE_CHANNEL_CODE = :interfaceChennelCode ");
    	sql.append(" and b.ORDER_TYPE = :orderType ");
    	sql.append(" and b.GOPAY_BANK_CODE = :bankCode ");
    	if(StringUtils.isNotBlank(across)){
    		sql.append(" and o.IS_CROSSBANK = :across ");
    	}
    	sql.append(" and b.TOTAL_CHECK_TIMES <= :totalCheckTimes ");
    	sql.append(" and b.SEND_BANK_TM >=to_date(:beginTime ,'yyyyMMddHH24miss') ");
    	sql.append(" and c.gopay_order_id is null");
    	
    	//sql.append(" order by b.TOTAL_CHECK_TIMES, b.GOPAY_ORDER_ID desc ");
    	sql.append(" order by b.SEND_BANK_TM asc ");
    	
    	Map<String, Object> params = new HashMap<String, Object>();
    	params.put("orderStatus", orderStatus);
    	params.put("bankBizProdCode", BisBankBusinessProd._09.value);
    	params.put("interfaceChennelCode", BisBankInterfaceChannel._00.value);
    	params.put("orderType", BankOrderType.GOPAY_BIS_ORDER);
    	params.put("bankCode", bank);
    	params.put("totalCheckTimes", 7);
    	if(modInt!=1){
	    	params.put("modInt", modInt);
	    	params.put("remainder", remainder);
    	}
    	if(StringUtils.isNotBlank(across)){
    		params.put("across", across);
    	}
    	params.put("beginTime", recentlyTime());
    	List<Object[]> list = commonQueryDAO.findBySql(sql.toString(), params, pageIndex, pageSize);
    	return list;
    }

	private String recentlyTime(){
		Calendar calendar = Calendar.getInstance();
		
		//开始时间--最近1天
		calendar.setTime(new Date());
		calendar.add(Calendar.DAY_OF_MONTH, -3);
		String beginTime=DateUtils.format(calendar.getTime(), "yyyyMMddHHmmss");
		
		return beginTime;
	}
//	private String buildBCDLTimeClause(){
//    	Calendar calendar = Calendar.getInstance();
//    	
//    	//开始时间--最近1天
//    	calendar.setTime(new Date());
//    	calendar.add(Calendar.DAY_OF_MONTH, -1);
//    	String beginTime=DateUtils.format(calendar.getTime(), "yyyyMMddHHmmss");
//    	
//    	StringBuilder sb=new StringBuilder(" and b.SEND_BANK_TM >to_date('"+beginTime+"','yyyyMMddHH24miss') ");
//    	
//    	return sb.toString();
//    }
	public List<String> getSendBankOrder(String bank) {
		List<Object[]> list = getCheckBcdlOrderByBank(bank,BankOrderStatus.ACCEPTED,modInt,remainder, across, 1, MAX_SIZE);
		List<String> orderIds = new ArrayList<String>();
		for (Object[] bankOrderId : list) {
			logger.error("label_"+label+"_mod_"+modInt+"_remainder_"+remainder+"orderId:"+bankOrderId[0]);
			orderIds.add(StringTools.checkNulltoString(bankOrderId[0]));
		}
		return orderIds;
	}
	
	private String getStlmEx(String gopayOrderId) {
        StringBuffer sql = new StringBuffer(250);
        Map<String, Object> map = new HashMap<String, Object>();
        sql.append(" SELECT ")
           .append(" STLM_EX, GOPAY_ORDER_ID ")
           .append(" FROM CPS_GEN_PAY_ORDER cp ")
           .append(" WHERE 1=1 ")
           .append(" AND cp.GOPAY_ORDER_ID =:gopayOrderId");
        map.put("gopayOrderId", gopayOrderId);
        List<Object[]> list = commonQueryDAO.findBySql(sql.toString(), map);
        if (list != null && list.size() > 0) {
            return StringTools.checkNulltoString(list.get(0)[0]);
        }
        return null;
    }

	private boolean isLargeCrossWorkTime(Date date) {
        int hour = date.getHours();
        int minute = date.getMinutes();
        if (hour < 9 || hour > 16 || (hour == 16 && minute > 50) || (hour == 9 && minute < 10)) {
            logger.info("BcdlOrderSendEmitterTaskImpl isLargeCrossWorkTime false");
            return false;
        }
        return true;
    }

	private void oneTestOrder(String bank, BcdlOrderSentinel sentinel){
		logger.error("bcdl_" + bank + ",执行一分钱测试操作，start");
		//获取该熔断器下最新的一笔11状态的一分钱测试订单
		try {
			BankOrder bankOrder = bankOrderManager.getSendOneTestOrder(sentinel.getSentinelId());
			if(bankOrder == null){
				return ;
			}
			String beanName = getSendBankBeanName(bank);
			if (false == SpringContextUtil.containsBean(beanName)) {
				logger.info("label_"+label+"spring bean does not exist: " + beanName);
				return;
			}
			
			BcdlOrderSendBankService sendBankService = (BcdlOrderSendBankService) SpringContextUtil
					.getBean(beanName);
			//发往银行
			logger.error("label_"+label+"一分钱测试银企直连 发送银行--开始 ，orderId=" + bankOrder.getOrderId() + ",bank=" + bank);
			BcdlResult result = sendBankService.sendBank(bankOrder,label);
			logger.error("label_"+label+"一分钱测试银企直连 发送银行--结束 ，orderId="+bankOrder.getOrderId()+",bank="+bank+",resultCode="+result.getResultCode());
			
			Map<String, String> param = new HashMap<String, String>();
			if (ProcCodeConstants.PROC_CODE_100E6027.equals(result.getResultCode()) ) {
				param.put("resultCode", "2");
				param.put("resultMsg", result.getErrorMsg());
				param.put("remark", "1");
				param.put("gopayOrderId", bankOrder.getOrderId());

				//add by zyt,2017-10-13 ,是否需要做失败的拒绝账务，
				if(result.isNeedRefund()){
					logger.info("发起失败拒绝账务：orderId:" + bankOrder.getOrderId());
					param.put("needRefund", "1");
				}

				/*notifyGass.setUrl(bankOrder.getRemark2());
				notifyGass.submit(param);*/ // 生产优化10期 lx httpclient 替换为 hessian
				gassPayService.bcdlNotifyGass(param);
			}else if(ProcCodeConstants.PROC_CODE_100S1000.equals(result.getResultCode()) ){
				param.put("resultCode", "1");
				param.put("remark", "1");
				param.put("gopayOrderId", bankOrder.getOrderId());
				/*notifyGass.setUrl(bankOrder.getRemark2());
				notifyGass.submit(param);*/ // 生产优化10期 lx httpclient 替换为 hessian
				gassPayService.bcdlNotifyGass(param);
			}else if(ProcCodeConstants.PROC_CODE_100E6047.equals(result.getResultCode()) ){
				logger.error("label_"+label+"银企直连 超时休眠--开始 ，orderId="+bankOrder.getOrderId()+",bank="+bank);
				Thread.sleep(5000);
				logger.error("label_"+label+"银企直连 超时休眠--结束 ，orderId="+bankOrder.getOrderId()+",bank="+bank);
			}else{
				param.put("resultCode", "3");
				param.put("remark", "1");
				param.put("gopayOrderId", bankOrder.getOrderId());
				/*notifyGass.setUrl(bankOrder.getRemark2());
				notifyGass.submit(param);*/ // 生产优化10期 lx httpclient 替换为 hessian
				gassPayService.bcdlNotifyGass(param);
			}
		} catch (GopayException | InterruptedException e) {
			logger.error("bcdl_" + bank + ",一分钱测试出现异常");
			e.printStackTrace();
		}
		//根据返回的
		logger.error("bcdl_" + bank + ",执行一分钱测试操作，end");
	}
	
	private String getSendBankBeanName(String bankCode) throws GopayException {
		String beanName = bankCode + "-BCDL";
		return beanName;
	}

	public BankOrderService getBankOrderService() {
		return bankOrderService;
	}

	public void setBankOrderService(BankOrderService bankOrderService) {
		this.bankOrderService = bankOrderService;
	}
    
	

    public void setBank(String bank) {
        this.bank = bank;
    }


	public CpsGeneralMainOrderQueryManager getMainOrderQuery() {
		return mainOrderQuery;
	}

	public void setMainOrderQuery(CpsGeneralMainOrderQueryManager mainOrderQuery) {
		this.mainOrderQuery = mainOrderQuery;
	}

	public BankOrderManager getBankOrderManager() {
		return bankOrderManager;
	}

	public void setBankOrderManager(BankOrderManager bankOrderManager) {
		this.bankOrderManager = bankOrderManager;
	}
	public void setRemainder(int remainder) {
        this.remainder = remainder;
    }

    public void setModInt(int modInt) {
        this.modInt = modInt;
    }

	public void setLabel(String label) {
		this.label = label;
	}

	public void setAcross(String across) {
		this.across = across;
	}

	public void setSentinel(BcdlOrderSentinel sentinel) {
		this.sentinel = sentinel;
	}

}
